package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.apis.article.IArticleClient;
import com.heima.audit.aliyun.GreenImageScan;
import com.heima.audit.aliyun.GreenTextScan;
import com.heima.audit.baidu.BaiduImageScan;
import com.heima.audit.baidu.BaiduTextScan;
import com.heima.audit.tess4j.Tess4jClient;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.service.*;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author shkstart
 * @create 2023-01-03-20:22
 */
@Service
@Slf4j
public class WmNewsAuditServiceImpl implements WmNewsAuditService {

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private BaiduImageScan baiduImageScan;

    @Autowired
    private BaiduTextScan baiduTextScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient articleClient;

    @Autowired
    private WmChannelService wmChannelService;

    @Autowired
    private WmUserService wmUserService;

    @Autowired
    private WmNewsService wmNewsService;

    @Autowired
    private WmSensitiveService wmSensitiveService;

    @Autowired
    private Tess4jClient tess4jClient;
    /**
     * 提取：调用文章自动审核(该方法会当做异步任务交给线程池中执行)
     * @param wmNews
     * @param contentImageList
     * @return
     */
    @GlobalTransactional
    @Async("taskExecutor")
    @Override
    public void  auditWmNews(WmNews wmNews, List<String> contentImageList) {

        try {
            TimeUnit.SECONDS.sleep(10);//默认处理耗时超过10秒
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        //1.准备待审核数据(文本和图片)
        //1.1准备文本资源（标题+内容文本+标签）
        String allText = this.prepareAllText(wmNews);
        //1.2准备图片资源（内容图片和封面图片）
        Set<String> allImage = this.prepareAllImage(wmNews,contentImageList);

        StringBuffer orcText = new StringBuffer();
        //遍历DCR识别每一张图片中的文本数据
        if (allImage.size() > 0){
            for (String url : allImage) {
                byte[] bytes = fileStorageService.downLoadFile(url);

                //图片识别文字审核---begin-----

                try {
                    //从byte[]转换为butteredImage
                    ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                    BufferedImage imageFile = ImageIO.read(in);
                    //识别图片的文字
                    String result = tess4jClient.doOCR(imageFile);
                    System.out.println("图片文字识别结果 "+result);
                    if (StringUtils.isNotBlank(result)){
                        orcText.append(result);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (TesseractException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        allText = orcText.append(allImage).toString();

        //2.本地DFA算法文本审核
        boolean flag = this.dfaTextScan(wmNews, allText);
        if (!flag){
            log.info("[文章自动审核]DFA审核出现问题，文章id:{}",wmNews.getId());
            return ;
        }
        //3.百度云文本审核（如果审核结果非正常block或者review,要阻断审核流程）
        flag = this.baiduTextScan(wmNews, allText);
        if (!flag){
            log.info("[文章自动审核]阿里云文本中审核出现问题，文章id:{}",wmNews.getId());
            return ;
        }
        //4.百度云图片审核（如果审核结果非正常block或者review,要阻断审核流程）
        flag = this.baiduImageScan(wmNews, allImage);
        if (!flag){
            log.info("[文章自动审核]阿里云图片中审核出现问题，文章id:{}",wmNews.getId());
            return ;
        }
        //5.处理文章发布
       this.doArticlePublish(wmNews);
    }

    @Autowired
    private CacheService cacheService;

    private Boolean dfaTextScan(WmNews wmNews , String allText){
        Boolean flag = true;
        //2.1查询所有的敏感词列表

        //redis缓存
        String redisKey = "sensitive:cache:list";
        List<String> sensitiveWordList = cacheService.lRange(redisKey, 0, -1);
        if (sensitiveWordList.isEmpty()){
            List<WmSensitive> wmSensitiveList = wmSensitiveService.list(Wrappers.<WmSensitive>lambdaQuery()
                    .select(WmSensitive::getSensitives));
            sensitiveWordList = wmSensitiveList.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            //将表中查询到的敏感词存储到Redis里面
            cacheService.lLeftPushAll(redisKey, sensitiveWordList);
        }

        //2.2初始化DFA词库
        SensitiveWordUtil.initMap(sensitiveWordList);
        //2.3检查文章内文本的敏感词
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(allText);
        //2.4根据检测结果进行处理
        if (resultMap.size() > 0){
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("DFA文本审核结果命中敏感词");
            wmNewsService.updateById(wmNews);
            flag = false;
        }
        return flag;
    }
    /**
     * 提取：处理文章发布
     * @param wmNews
     * @return
     */
    private void doArticlePublish(WmNews wmNews){
        //4.1获取文章发布时间和系统当前时间
        long publishTime = wmNews.getPublishTime().getTime();
        long currentTime = System.currentTimeMillis();
        //4.2获取发布时间未到（发布时间>系统当前时间，改变状态为8）
        if (publishTime > currentTime){
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
            wmNews.setReason("自动审核通过，待发布");
            wmNewsService.updateById(wmNews);
            log.info("[文章自动审核]文章自动审核通过待发布，文章id:{}",wmNews.getId());
        }else{
            //4.3获取发布时间未到（发布时间<=系统当前时间，改变状态为9）
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setReason("自动审核通过，已发布");
            wmNewsService.updateById(wmNews);

            ArticleDto articleDto = new ArticleDto();
            articleDto.setId(wmNews.getArticleId());
            articleDto.setTitle(wmNews.getTitle());
            articleDto.setContent(wmNews.getContent());
            articleDto.setLabels(wmNews.getLabels());
            articleDto.setLayout(wmNews.getType());
            articleDto.setImages(wmNews.getImages());
            articleDto.setPublishTime(wmNews.getPublishTime());
            if (articleDto.getId() == null){
                articleDto.setCreatedTime(new Date());
            }
            WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
            if (wmChannel != null){
                articleDto.setChannelId(wmChannel.getId());
                articleDto.setChannelName(wmChannel.getName());
            }
            WmUser wmUser = wmUserService.getById(wmNews.getUserId());
            if (wmUser != null){
                articleDto.setAuthorId(wmUser.getApAuthorId().longValue());
                articleDto.setAuthorName(wmChannel.getName());
            }
            //调用feign接口创建和更新APP文章
            ResponseResult result = articleClient.saveOrUpdateArticle(articleDto);
            Integer code = result.getCode();
            if (code != 200){
                throw new CustomException(AppHttpCodeEnum.INVOKE_ARTICLE_FEIN_ERROR);
            }
            //获取feign接口响应结果到里的APP文章id
            Long articleId = Long.valueOf(String.valueOf(result.getData()));

            //更新app文章的id到自媒体文章表中
            wmNews.setArticleId(articleId);
            wmNewsService.updateById(wmNews);
            log.info("[文章自动审核]文章自动审核通过已发布，文章id:{}",wmNews.getId());
        }
    }

    /**
     * 提取：阿里云图片审核（如果审核结果非正常block或者review,要阻断审核流程）
     * @param wmNews
     * @param allImage
     * @return
     */
    private Boolean baiduImageScan(WmNews wmNews,Set<String> allImage){
        Boolean flag = true;
        if (allImage.size()>0){
            for (String url : allImage) {
                byte[] bytes = fileStorageService.downLoadFile(url);
                int result = baiduImageScan.imageScan(bytes);
                if (result == 2) {
                    wmNews.setStatus(WmNews.Status.FAIL.getCode());
                    wmNews.setReason("阿里云图片审核结果违规");
                    wmNewsService.updateById(wmNews);
                    flag = false;
                    break;
                } else if (result == 3) {
                    wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                    wmNews.setReason("阿里云云图片审核结果违规");
                    wmNewsService.updateById(wmNews);
                    flag = false;
                    break;
                } else if (result == 4) {
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }

    /**
     * 提取：阿里云文本审核（如果审核结果非正常block或者review,要阻断审核流程）
     * @param wmNews
     * @param text
     * @return
     */
    private Boolean baiduTextScan(WmNews wmNews, String text){
        Boolean flag = true;
        int result = baiduTextScan.textScan(text);
        if (result == 2){
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("阿里云文本审核结果违规");
            wmNewsService.updateById(wmNews);
            flag = false;
        }else if (result == 3){
            wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNews.setReason("阿里云图片审核结果违规");
            wmNewsService.updateById(wmNews);
            flag = false;
        }else{
            flag = false;
        }
        return flag;
    }

    /**
     * 提取：准备图片资源（内容图片和封面图片）
     * @param wmNews
     * @param contentImageList
     * @return
     */
    private Set<String> prepareAllImage(WmNews wmNews, List<String> contentImageList) {
        String images = wmNews.getImages();
        List<String> coverImageList = Arrays.asList(images.split(","));
        Set<String> allImageSet = new HashSet<>();
        allImageSet.addAll(contentImageList);//内容图片
        allImageSet.addAll(coverImageList);//封面图片
        return allImageSet;
    }

    /**
     * 提取：准备文本资源（标题+内容文本+标签）
     * @param wmNews
     * @return
     */
    private String prepareAllText(WmNews wmNews) {
        StringBuffer text = new StringBuffer();
        text.append(wmNews.getTitle());
        text.append(wmNews.getLabels());
        String content = wmNews.getContent();
        if (StringUtils.isNotBlank(content)){
            List<Map> mapList = JSON.parseArray(content, Map.class);
            if (mapList != null && mapList.size() > 0){
                for (Map<String, String> map : mapList) {
                    String type = map.get("type");
                    if ("text".equals(type)){
                        String contentText = map.get("value");
                        text.append(contentText);
                    }
                }
            }
        }
        return text.toString();
    }
}
